<?php

namespace lc\activity\lottery;

use lc\activity\model\LotteryAward;
use lc\activity\model\LotteryAwardList;
use lc\activity\model\LotteryConfig;
use lc\activity\model\LotteryIps;
use lc\activity\model\LotteryLogs;
use lc\activity\model\LotteryUserExtra;
use lc\activity\model\LotteryWinner;
use lc\activity\RedPackAct;
use lc\cache\redis\Redis;
use think\facade\Config;
use think\facade\Db;

class LotteryRedisAct extends LotteryService
{
    protected $redis = null;

    /**
     * 抽奖配置 在 redis 的 hash key
     * @var string
     */
    protected $lotteryKey = 'lottery_';

    /**
     * 抽奖记录 在 redis 的 list key
     * @var string
     */
    protected $lotLogsKey = 'lotLogs_';

    /**
     * 用户数据记录 在 redis 的 hash key
     * @var string
     */
    protected $userRcdKey = 'userRcd_';

    /**
     * IP数据记录 在 redis 的 list key
     * @var string
     */
    protected $ipsRcdKey = 'ipsRcd_';

    /**
     * 奖池数据 在 redis 的 list key
     * @var string
     */
    protected $awardKey = 'awards_';

    /**
     * 奖品列表数据 在 redis 的 list key
     * @var string
     */
    protected $pondsKey = 'ponds_';

    const DAY_REQ_COUNT     = '_dayReqCount';
    const MAX_REQ_COUNT     = '_maxReqCount';
    const DAY_JOIN_COUNT    = '_dayJoinCount';
    const MAX_JOIN_COUNT    = '_maxJoinCount';
    const DAY_WIN_COUNT     = '_dayWinCount';
    const MAX_WIN_COUNT     = '_maxWinCount';
    const KEY_LAST_DAY      = '_lastDay';

    /**
     * 当前时间，类似 20210422，用于同步脚本
     * @var string
     */
    protected $currDay;

    protected $pid;
    protected $uuid;

    /**
     * @param string 	$appId
     * @param string	$appSecret
     * @param $user
     * @param $pid		项目ID
     */
    public function __construct(string $appId, string $appSecret, $user, $pid)
    {
        $this->user         = $user;
        $this->uuid			= $user->u_uid;
        $this->appId        = $appId;
        $this->appSecret    = $appSecret;
        $this->pid    		= $pid;
        $this->ip           = request()->ip();
        $this->time         = time();
        $this->today        = strtotime('today');
        $this->currDay      = date('Ymd');
        $this->redis        = Redis::instance();
        $this->lotteryKey   .= $this->pid;
        $this->ipsRcdKey    .= $this->pid;
        $this->userRcdKey   .= $this->pid;
        $this->lotLogsKey   .= $this->pid;
        $this->awardKey     .= $this->pid;
        $this->pondsKey     .= $this->pid;

        $this->redis->select(Config::get('lc.redis.db'));
    }

    /**
     * @desc    抽奖
     * @return  array
     * @throws  \lc\wxpay\base\WxPayException
     * @throws  \think\db\exception\DbException
     */
    public function run()
    {
        $this->lotteryStartOrEnd();
        if ($this->response['code'] !== 0) {
            return $this->response;
        }

        $this->setIpsRecord(LotteryIps::IP_TYPE_REQUEST);
        $this->initLotteryLog();
        if ($this->response['code'] !== 0) {
            return $this->response;
        }
        $this->setUserExtraRecord(LotteryUserExtra::USER_EXTRA_TYPE_REQUEST);

        // 2. 判断用户是否有抽奖次数，并扣除相应抽奖次数
        if ($this->reduceUserCount() === 0) {
            return $this->response;
        }

        // 3. 判断抽奖活动参与次数和参与人数
        if ($this->checkLotteryCount() === 0) {
            $this->responseNotAward();
            return $this->response;
        }

        // 4. 判断用户抽奖参与次数
        if ($this->checkUserLotteryCount() === 0) {
            $this->responseNotAward();
            return $this->response;
        }
        $this->setIpsRecord(LotteryIps::IP_TYPE_JOIN);
        $this->setUserExtraRecord(LotteryUserExtra::USER_EXTRA_TYPE_JOIN);

        // 4. 判断奖池发奖时间
        if ($this->timeIfCanWin() === 0) {
            $this->responseNotAward();
            return $this->response;
        }

        // 6. 判断用户中奖次数
        if ($this->checkUserWinCount() === 0) {
            $this->responseNotAward();
            return $this->response;
        }

        // 7. 判断IP中奖次数
        if ($this->checkIpLimitWinCount() === 0) {
            $this->responseNotAward();
            return $this->response;
        }

        // 8. 列表抽奖
        if ($this->config->l_lottery_type == LotteryConfig::LOTTERY_TYPE_RANDOM) {
            if (rand(0, 10000) > $this->config->l_rand) {
                $this->lotteryLog('随机未中奖');
                $this->response['code'] = LotteryConfig::RANDOM_NOT_WIN;
                $this->responseNotAward();
                return $this->response;
            }
            $winAward = $this->randomLottery();
        } else {
            $winAward = $this->listLottery();
        }

        if (!$winAward) {
            $this->lotteryLog('奖池暂无奖品');
            $this->response['code'] = LotteryConfig::NO_AWARD;
            $this->responseNotAward();
            return $this->response;
        }

        // 9. 更新奖池
        $winnerId = $this->insertWinner($winAward);
        if (!$winnerId) {
            // 更新奖池失败，则不中奖
            $this->lotteryLog('更新奖池失败');
            $this->response['code'] = LotteryConfig::UPDATE_STOCK_FAIL;
            $this->responseNotAward();
            return $this->response;
        }

        // 10. 发奖
        switch ($winAward->a_award_type) {
            case LotteryAward::AWARD_TYPE_RED_PACK_CASH:
            case LotteryAward::AWARD_TYPE_RED_PACK_BALANCE:
                // 企业支付发红包
                $redPackAct = new RedPackAct();
                $redPackAct->setPid($this->config->l_pid);
                $sendAwardRes = $redPackAct->send($this->user->toArray(), $winAward->a_price);
                break;
            case LotteryAward::AWARD_TYPE_NORMAL:
            default:
                // 普通奖品
                $sendAwardRes = ['status' => 1, 'msg' => '发奖成功'];
                break;
        }

        // 10. 抽奖结果
        if ($sendAwardRes['status'] === 1) {
            $this->setIpsRecord(LotteryIps::IP_TYPE_WIN);
            $this->setUserExtraRecord(LotteryUserExtra::USER_EXTRA_TYPE_WIN);

            $this->lotteryLog("抽中奖品：{$winAward->a_awardname}");

            $this->response['code'] = 0;
            $this->response['msg']  = "恭喜抽中奖品: {$winAward->a_awardname}";
            $this->response['data'] = [
                'aId'       => $winAward->a_id,
                'awardId'   => $winAward->a_awardid,
                'awardName' => $winAward->a_awardname,
                'awardCode' => isset($winAward->a_code) ? $winAward->a_code : '',
                'awardPrice'=> isset($winAward->a_price) ? $winAward->a_price : 0,
                'wId'       => $winnerId,
                'isReceive' => 0
            ];

            return $this->response;
        } else {
            // 发送红包或充值话费等操作失败，则不中奖
			LotteryWinner::where('w_id', $winnerId)->delete();
            if ($this->config->l_lottery_type == LotteryConfig::LOTTERY_TYPE_RANDOM) {
                // 回退奖池
                $this->redis->rPush($this->awardKey, json_encode($winAward, 256));
            } else {
                // 回退奖池
                $this->redis->rPush($this->pondsKey . "_{$winAward->a_id}", $winAward->a_awardname);
            }

            $this->lotteryLog($sendAwardRes['msg']);
            $this->response['code'] = LotteryConfig::AWARD_SEND_FAIL;
            $this->responseNotAward();
            return $this->response;
        }
    }

    /**
     * @desc 判断活动是否未开始或已结束
     */
    private function lotteryStartOrEnd()
    {
        $redisConfig = $this->redis->hGetAll($this->lotteryKey);
        if (!$redisConfig) {
            $dbConfig = LotteryConfig::connect('main')->where(['l_appid' => $this->appId, 'l_pid' => $this->pid])->find();
            if (!$dbConfig) {
                $this->response['code'] = LotteryConfig::STATUS_EXCEPTION;
                $this->response['msg']  = 'APPID 或 PID 错误，未匹配到抽奖活动.';
                return;
            } elseif ($dbConfig->l_secret != $this->appSecret) {
                $this->response['code'] = LotteryConfig::STATUS_EXCEPTION;
                $this->response['msg']  = 'APPID 与 APP_SECRET 不匹配.';
                return;
            }

            LotteryConfig::setRedisLotteryConfig($this->redis, $this->lotteryKey, $dbConfig);
            $this->config = $dbConfig;
        } else {
            $this->config = json_decode(json_encode($redisConfig));
        }

        if (strtotime($this->config->l_start_time) > $this->time) {
            $this->response['code'] = LotteryConfig::STATUS_EXCEPTION;
            $this->response['msg']  = "活动于 {$this->config->l_start_time} 正式开始.";
            return;
        } elseif (strtotime($this->config->l_end_time) < $this->time) {
            $this->response['code'] = LotteryConfig::STATUS_EXCEPTION;
            $this->response['msg']  = "活动于 {$this->config->l_end_time} 已结束，敬请期待下次活动.";
            return;
        }
    }

    /**
     * @desc 初始化抽奖日志
     */
    private function initLotteryLog()
    {
        // 抽奖日志
        $key = $this->uuid . '_' . intval($this->time / 2);
        if (!$this->redis->hGet($this->lotLogsKey, $key)) {
            $this->log       		= new LotteryLogs();
            $this->log->ll_key     	= $key;
            $this->log->ll_uid     	= $this->uuid;
            $this->log->ll_phone   	= !empty($this->user->u_phone) ? $this->user->u_phone : '';
            $this->log->ll_status  	= null;
            $this->log->ll_ip      	= $this->ip;
            $this->log->ll_day     	= $this->today;
            $this->log->ll_create   = date('Y-m-d H:i:s');
            $this->log->ll_marks    = null;
        } else {
            $this->response['code'] = LotteryConfig::REQUEST_FREQUENT;
            $this->response['msg']  = '请求频繁，请稍后重试';
        }
    }

    /**
     * @desc    IP记录
     * @param   int $type
     */
    private function setIpsRecord($type)
    {
        if ($type == LotteryIps::IP_TYPE_JOIN) {
            $this->redis->hIncrBy($this->ipsRcdKey, $this->ip . self::DAY_JOIN_COUNT, 1);
            $this->redis->hIncrBy($this->ipsRcdKey, $this->ip . self::MAX_JOIN_COUNT, 1);
        } elseif ($type == LotteryIps::IP_TYPE_WIN) {
            $this->redis->hIncrBy($this->ipsRcdKey, $this->ip . self::DAY_WIN_COUNT, 1);
            $this->redis->hIncrBy($this->ipsRcdKey, $this->ip . self::MAX_WIN_COUNT, 1);
        } else {
            $lastDay = $this->redis->hGet($this->ipsRcdKey, $this->ip . self::KEY_LAST_DAY);
            if (!$lastDay) {
                $this->redis->hSet($this->ipsRcdKey, $this->ip . self::DAY_REQ_COUNT, 1);
                $this->redis->hSet($this->ipsRcdKey, $this->ip . self::MAX_REQ_COUNT, 1);
                $this->redis->hSet($this->ipsRcdKey, $this->ip . self::DAY_JOIN_COUNT, 0);
                $this->redis->hSet($this->ipsRcdKey, $this->ip . self::MAX_JOIN_COUNT, 0);
                $this->redis->hSet($this->ipsRcdKey, $this->ip . self::DAY_WIN_COUNT, 0);
                $this->redis->hSet($this->ipsRcdKey, $this->ip . self::MAX_WIN_COUNT, 0);
                $this->redis->hSet($this->ipsRcdKey, $this->ip . self::KEY_LAST_DAY, $this->today);
                $this->redis->rPush("ipsAdd_{$this->pid}_{$this->currDay}", $this->ip);
            } else {
                if ($lastDay && $lastDay != $this->today) {
                    $this->redis->hSet($this->ipsRcdKey, $this->ip . self::DAY_REQ_COUNT, 0);
                    $this->redis->hSet($this->ipsRcdKey, $this->ip . self::DAY_JOIN_COUNT, 0);
                    $this->redis->hSet($this->ipsRcdKey, $this->ip . self::DAY_WIN_COUNT, 0);
                    $this->redis->hSet($this->ipsRcdKey, $this->ip . self::KEY_LAST_DAY, $this->today);
                }
                $this->redis->hIncrBy($this->ipsRcdKey, $this->ip . self::DAY_REQ_COUNT, 1);
                $this->redis->hIncrBy($this->ipsRcdKey, $this->ip . self::MAX_REQ_COUNT, 1);
                $this->redis->rPush("ipsUpd_{$this->pid}_{$this->currDay}", $this->ip);
            }
        }
    }

    /**
     * @desc    记录用户参与，中奖
     * @param   int $type
     */
    private function setUserExtraRecord(int $type)
    {
        if ($type == LotteryUserExtra::USER_EXTRA_TYPE_JOIN) {
            $this->redis->hIncrBy($this->userRcdKey, $this->uuid . self::DAY_JOIN_COUNT, 1);
            $this->redis->hIncrBy($this->userRcdKey, $this->uuid . self::MAX_JOIN_COUNT, 1);
        } elseif ($type == LotteryUserExtra::USER_EXTRA_TYPE_WIN) {
            $this->redis->hIncrBy($this->userRcdKey, $this->uuid . self::DAY_WIN_COUNT, 1);
            $this->redis->hIncrBy($this->userRcdKey, $this->uuid . self::MAX_WIN_COUNT, 1);
        } else {
            // 用户统计
            $lastDay = $this->redis->hGet($this->userRcdKey, $this->uuid . self::KEY_LAST_DAY);
            if (!$lastDay) {
                $this->redis->hSet($this->userRcdKey, $this->uuid . self::DAY_JOIN_COUNT, 0);
                $this->redis->hSet($this->userRcdKey, $this->uuid . self::MAX_JOIN_COUNT, 0);
                $this->redis->hSet($this->userRcdKey, $this->uuid . self::DAY_WIN_COUNT, 0);
                $this->redis->hSet($this->userRcdKey, $this->uuid . self::MAX_WIN_COUNT, 0);
                $this->redis->hSet($this->userRcdKey, $this->uuid . self::KEY_LAST_DAY, $this->today);
                $this->redis->rPush("userAdd_{$this->pid}_{$this->currDay}", $this->uuid);

                // set 抽奖配置
                $this->redis->hIncrBy($this->lotteryKey, 'l_curr_join_count', 1);
                $this->redis->hIncrBy($this->lotteryKey, 'l_curr_join_user', 1);

                $this->isNewUser = 1;
            } else {
                if ($lastDay && $lastDay != $this->today) {
                    $this->redis->hSet($this->userRcdKey, $this->uuid . self::DAY_JOIN_COUNT, 0);
                    $this->redis->hSet($this->userRcdKey, $this->uuid . self::MAX_JOIN_COUNT, 0);
                    $this->redis->hSet($this->userRcdKey, $this->uuid . self::KEY_LAST_DAY, $this->today);
                }

                $this->redis->rPush("userUpd_{$this->pid}_{$this->currDay}", $this->uuid);
                $this->redis->hIncrBy($this->lotteryKey, 'l_curr_join_count', 1);
            }
        }
    }

    /**
     * @desc    判断用户是否有抽奖次数，并减少相应次数
     * @return  int
     */
    private function reduceUserCount()
    {
        $field      = $this->config->l_field;
        $fieldVal   = $this->config->l_field_val;
        $count      = $this->user->$field;
        // 处理用户的抽奖资格比如，扣除积分，减少抽奖次数之类的操作
        if (($fieldVal > 0 && $count >= $fieldVal) || ($fieldVal == 0 && $count > $fieldVal)) {
            switch ($fieldVal) {
                case 0:
                    // l_field_val默认值为1，如果这个值为0，则需要特殊处理，分享多次只能抽奖1次之类的情况
                    $newVal = 0;
                    break;
                case 1:
                default:
                    $newVal = $count - $fieldVal;
                    break;
            }
            $this->user->$field = $newVal;
            if (Db::name('user')->where('u_uid', $this->uuid)->update([$field => $newVal])) {
                return 1;
            } else {
                $this->lotteryLog('扣除用户抽奖次数失败');
                $this->response['code'] = LotteryConfig::REDUCE_USER_COUNT_FAIL;
                return 0;
            }
        } else {
            $this->lotteryLog('暂无抽奖次数');
            $this->response['code'] = LotteryConfig::USER_NO_COUNT;
            $this->response['msg']  = '抽奖次数用完了.';
            return 0;
        }
    }

    /**
     * @desc    判断活动参与次数或人数
     * @return  int
     */
    private function checkLotteryCount()
    {
        // 判断最大参与次数
        $currJoinUser = $this->redis->hGet($this->lotteryKey, 'l_curr_join_user');
        $maxJoinUser  = $this->config->l_max_join_user;
        if ($this->isNewUser && $maxJoinUser > 0 && $currJoinUser > $maxJoinUser) {
            $this->response['code'] = LotteryConfig::MAX_JOIN_USER_LIMIT;
            $this->lotteryLog("最大抽奖用户数 {$maxJoinUser} 已满，无法再次中奖");
            return 0;
        }
        // 判断最大参与人数
        $currJoinCount = $this->redis->hGet($this->lotteryKey, 'l_curr_join_count');
        $maxJoinCount  = $this->config->l_max_join_count;
        if ($maxJoinCount > 0 && $currJoinCount >= $maxJoinCount) {
            $this->response['code'] = LotteryConfig::MAX_JOIN_COUNT_LIMIT;
            $this->lotteryLog("最大抽奖次数 {$maxJoinCount} 已满，无法再次中奖");
            return 0;
        }

        return 1;
    }

    /**
     * @desc 	判断当前用户当天或活动期间参与抽奖次数，并写入抽奖日志
     * @return 	int
     */
    private function checkUserLotteryCount()
    {
        $lastDay = $this->redis->hGet($this->userRcdKey, $this->uuid . self::KEY_LAST_DAY);
        if ($lastDay == $this->today) {
            $dayJoinCount = $this->redis->hGet($this->userRcdKey, $this->uuid . self::DAY_JOIN_COUNT);
            $dailyCount   = $this->config->l_daily_count;
            if ($dailyCount > 0 && $dayJoinCount && $dayJoinCount >= $dailyCount) {
                $this->response['code'] = LotteryConfig::USER_TODAY_JOIN_LIMIT;
                $this->lotteryLog("今日参与次数已满，最大次数 {$dailyCount}");
                return 0;
            }
        }
        $maxJoinCount = $this->redis->hGet($this->userRcdKey, $this->uuid . self::MAX_JOIN_COUNT);
        $confMaxCount = $this->config->l_max_count;
        if ($confMaxCount > 0 && $maxJoinCount && $maxJoinCount >= $confMaxCount) {
            $this->response['code'] = LotteryConfig::USER_MAX_JOIN_LIMIT;
            $this->lotteryLog("活动期间参与次数已满，最大次数 {$confMaxCount}");
            return 0;
        }
        return 1;
    }

    /**
     * @desc    判断中奖时间
     * @return  int
     */
    private function timeIfCanWin()
    {
        $hour 	  	= date('G', $this->time);
        $startNoCan = (!is_null($this->config->l_win_start) && $this->config->l_win_start > 0) && $hour < $this->config->l_win_start;
        $endNoCan   = (!is_null($this->config->l_win_end) && $this->config->l_win_end > 0) && $hour > $this->config->l_win_end;
        if ($startNoCan || $endNoCan) {
            $this->response['code'] = LotteryConfig::TIME_LIMIT;
            $this->lotteryLog('当前时间不允许中奖');
            return 0;
        }
        return 1;
    }

    /**
     * @desc    判断用户今日或活动期间中奖次数
     * @return  int
     */
    private function checkUserWinCount()
    {
        $lastDay = $this->redis->hGet($this->userRcdKey, $this->uuid . self::KEY_LAST_DAY);
        if ($lastDay && $lastDay == $this->today) {
            // 判断今日最大中奖次数
            $dayWinCount  = $this->redis->hGet($this->userRcdKey, $this->uuid . self::DAY_WIN_COUNT);
            $confWinCount = $this->config->l_day_win_count;
            if ($confWinCount > 0 && $dayWinCount && $dayWinCount >= $confWinCount) {
                $this->response['code'] = LotteryConfig::USER_TODAY_WIN_LIMIT;
                $this->lotteryLog("当日中奖次数 {$confWinCount} 已满，无法再次中奖");
                return 0;
            }
        }
        // 判断活动期间最大中奖次数
        $maxWinCount  = $this->redis->hGet($this->userRcdKey, $this->uuid . self::MAX_WIN_COUNT);
        $confMaxCount = $this->config->l_max_win_count;
        if ($confMaxCount > 0 && $maxWinCount && $maxWinCount >= $confMaxCount) {
            $this->response['code'] = LotteryConfig::USER_MAX_WIN_LIMIT;
            $this->lotteryLog("活动期间中奖次数 {$confMaxCount} 已满，无法再次中奖");
            return 0;
        }

        return 1;
    }

    /**
     * @desc    判断今日或活动期间IP中奖限制
     * @return  int
     */
    private function checkIpLimitWinCount()
    {
        // 判断今日最大中奖次数
        $ipDayWinCount = $this->redis->hGet($this->ipsRcdKey, $this->ip . self::DAY_WIN_COUNT);
        $dailyIpLimit  = $this->config->l_daily_ip_limit;
        if ($dailyIpLimit > 0 && $ipDayWinCount && $ipDayWinCount >= $dailyIpLimit) {
            $this->response['code'] = LotteryConfig::IP_TODAY_WIN_LIMIT;
            $this->lotteryLog("该IP {$this->ip}，当日中奖次数 {$dailyIpLimit} 已满，无法再次中奖");
            return 0;
        }
        // 判断活动期间最大中奖次数
        $ipMaxWinCount = $this->redis->hGet($this->ipsRcdKey, $this->ip . self::MAX_WIN_COUNT);
        $maxIpLimit    = $this->config->l_max_ip_limit;
        if ($maxIpLimit > 0 && $ipMaxWinCount && $ipMaxWinCount >= $maxIpLimit) {
            $this->response['code'] = LotteryConfig::IP_MAX_WIN_LIMIT;
            $this->lotteryLog("该IP {$this->ip}，活动期间中奖次数 {$maxIpLimit} 已满，无法再次中奖");
            return 0;
        }
        return 1;
    }

    /**
     * @desc    修改对应抽奖 log 的 status 状态，用于记录用户的每次抽奖结果
     * @param   string $status 抽奖结果状态
     */
    private function lotteryLog($status)
    {
        $this->log->ll_status = $status;

        $this->redis->hSet($this->lotLogsKey, $this->log->ll_key, json_encode($this->log->toArray(), 256));
    }

    /**
     * @desc	随机抽奖
     * @return  array|mixed
     */
    private function randomLottery()
    {
        $len = $this->redis->lLen($this->awardKey);
        if ($len == 0) {
            LotteryAward::where('a_uid', 0)
                ->order('a_start', 'asc')
                ->order('a_id', 'asc')
                ->select()
                ->each(function ($item) {
                    // 把奖品放到池子里，建议这一步操作在后台，开始活动时进行
                    $this->redis->rPush($this->awardKey, json_encode($item, 256));
                });
            LotteryAward::where('a_uid = 0')->update(['a_uid' => -1]);
        }

        $award = json_decode($this->redis->lPop($this->awardKey));
        if ($award && $award->a_uid == 0 && $award->a_start <= $this->time) {
            return $award;
        } elseif ($award) {
            // 弹出的奖品如果发奖时间小于当前时间，则放回奖池
            $this->redis->lPush($this->awardKey, json_encode($award));
        }
        return [];
    }

    /**
     * @desc    列表抽奖
     * @return  array
     */
    private function listLottery()
    {
        if (!$this->redis->hLen($this->pondsKey)) {
            // 把奖品放到池子里，建议这一步操作在后台，开始活动时进行
            LotteryAwardList::where(function ($query) {
					$query->where("a_state = 1 and a_received + 1 <= a_number");
                })
                ->select()
                ->each(function ($item) {
                    $this->redis->hSet($this->pondsKey, $item->a_id, json_encode($item, 256));
                    $total = $item->a_number - $item->a_received;
                    for ($i = 0; $i < $total; $i++) {
                        $this->redis->rPush($this->pondsKey . "_{$item->a_id}", $item->a_awardname);
                    }
                });
        }
        $redisAwardList = $this->redis->hGetAll($this->pondsKey);

        $win    = mt_rand(1, 10000);
        $area   = 0;
        $award  = [];
        if ($redisAwardList) {
            foreach ($redisAwardList as $item) {
                $item = json_decode($item);
                $area += $item->a_rate;
                if ($win <= $area) {
                    $award = $item;
                    break;
                }
            }
        }

        if ($award) {
            if ($this->redis->lPop($this->pondsKey . "_{$award->a_id}")) {
                return $award;
            }
        }
        return [];
    }

    /**
     * @desc    插入中奖记录
     * @param   $award 	中奖奖品
     * @return  int 	winnerId
     */
    private function insertWinner($award)
    {
		$winner = LotteryWinner::create([
			'w_uid' 		=> $this->uuid,
			'w_aid' 		=> $award->a_id,
			'w_award_id' 	=> $award->a_awardid,
			'w_award_code' 	=> isset($award->a_code) ? $award->a_code : '',
			'w_award_name' 	=> $award->a_awardname,
			'w_award_price' => $award->a_price,
			'w_win_time' 	=> date('Y-m-d H:i:s', $this->time),
			'w_ip' 			=> $this->ip
		]);
		if ($winner->w_id) {
			return $winner->w_id;
		} else {
			if ($this->config->l_lottery_type == LotteryConfig::LOTTERY_TYPE_RANDOM) {
				// 回退奖池
				$this->redis->rPush($this->awardKey, json_encode($award, 256));
				return 0;
			} else {
				$this->redis->rPush($this->pondsKey . "_{$award->a_id}", $award->a_awardname);
				return 0;
			}
		}
    }

    /**
     * @desc 未中奖情况，判断是否有默认奖品
     */
    private function responseNotAward()
    {
        if ($this->response['data']['awardId'] > 0 || $this->config->l_default_award == 0) {
            return;
        }

        if ($this->config->l_lottery_type != LotteryConfig::LOTTERY_TYPE_RANDOM) {
            return;
        }
        $key = $this->awardKey;
        $len = $this->redis->lLen($key);
        $redisAward = $this->redis->lrange($key, 0, $len - 1);
        if ($redisAward) {
            return;
        }
        // 遍历，并移除
        $lremRes = 0;
        foreach ($redisAward as $item) {
            $origin = $item;
            $temp   = json_decode($item);
            if ($temp->a_awardid == $this->config->l_default_award && $temp->a_uid == 0) {
                $winAward = $temp;
                $lremRes  = $this->redis->lrem($key, $origin, 1);
                break;
            }
        }

        if (!empty($winAward) && $lremRes) {
            $winnerId = $this->insertWinner($winAward);
            if ($winnerId) {
                $this->lotteryLog("默认中奖 {$winAward->a_awardname}");

                $this->response['code'] = LotteryConfig::WIN_DEFAULT;
                $this->response['msg']  = "恭喜抽中奖品: {$winAward->a_awardname}";
                $this->response['data'] = [
                    'aId'           => $winAward->a_id,
                    'awardId'       => $winAward->a_awardid,
                    'awardName'     => $winAward->a_awardname,
                    'awardCode'     => isset($winAward->a_code) ? $winAward->a_code : '',
                    'awardPrice'    => isset($winAward->a_price) ? $winAward->a_price : 0,
                    'wId'           => $winnerId,
                    'isReceive'     => 0
                ];
            }
        }
    }
}